#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""docstring
models
"""
import uuid
import hashlib
from random import choice
from datetime import datetime
from werkzeug import cached_property, security
from sqlalchemy.ext.hybrid import hybrid_property
from flask.ext.sqlalchemy import BaseQuery
from flask.ext.principal import RoleNeed, UserNeed, Permission
from planet.extensions import db, cache

password_secret = 'lawliet'

def create_token(length=16):
    chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    salt = ''.join([choice(chars) for i in range(length)])
    return salt

class UserQuery(BaseQuery):
    def authenticate(self, account, password):
        user = self.filter(db.or_(User.username==account, 
                                  User.email==account)).first()
        if user:
            authenticated = user.check_password(password)
        else:
            authenticated = False

        return user, authenticated

    def search(self, key):
        query = self.filter(db.or_(User.email==key,
                                   User.nickname.ilike('%'+key+'%'),
                                   User.username.ilike('%'+key+'%')))
        return query

    def get_by_username(self, username):
        user = self.filter(User.username==username).first()
        if user is None:
            abort(404)
        return user

    def from_identity(self, identity):
        try:
            user = self.get(identity.id) if identity.id else None
        except ValueError:
            user = None

        if user:
            identity.provides.update(user.provides)

        identity.user = user
        return user


class User(db.Model):
    query_class = UserQuery

    ROOT = 1
    ADMIN = 10
    OPERATOR = 500
    MEMBER = 1000

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, index=True)
    email = db.Column(db.String(100), unique=True, nullable=False)
    _password = db.Column("password", db.String(100), nullable=False)
    role = db.Column(db.Integer, default=MEMBER)
    created = db.Column(db.DateTime, default=datetime.utcnow)
    updated = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    last_login_at = db.Column(db.DateTime)
    current_login_at = db.Column(db.DateTime)
    last_login_ip = db.Column(db.String(15))
    current_login_ip = db.Column(db.String(15))
    active = db.Column(db.Boolean, default=False)
    code = db.Column(db.String(40),default=hashlib.sha1(str(uuid.uuid1())).hexdigest())
    code_datetime = db.Column(db.DateTime, default=datetime.utcnow)

    profile = db.relationship('Profile', uselist=False, backref='user')

    @cached_property
    def status_message(self):
        dic = {
            0:'blocked',
            1:'active'
        }
        return dic.get(self.active)

    def __init__(self, *args, **kwargs):
        super(User, self).__init__(*args, **kwargs)

    def __str__(self):
        return self.username

    def __repr__(self):
        return "<%s>" % self

    @hybrid_property
    def password(self):
        return self._password

    @password.setter
    def password(self, password):
        salt = create_token(8)
        hsh = hashlib.sha1(salt + password + password_secret).hexdigest()
        self._password = "%s$%s" % (salt, hsh)

    def check_password(self, password):
        if self.password is None:
            return False
        salt, hsh = self.password.split('$')
        verify = hashlib.sha1(salt + password + password_secret).hexdigest()
        return verify == hsh

    @cached_property
    def provides(self):
        needs = [RoleNeed('authenticated'),
                 UserNeed(self.id)]

        if self.is_operator:
            needs.append(RoleNeed('operator'))

        if self.is_admin:
            needs.append(RoleNeed('admin'))

        if self.is_root:
            needs.append(RoleNeed('root'))

        return needs

    @property
    def is_root(self):
        return self.role == self.ROOT and self.id == 1

    @property
    def is_admin(self):
        return self.role <= self.ADMIN 

    @property
    def is_operator(self):
        return self.role <= self.OPERATOR


class Profile(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, 
                          db.ForeignKey('user.id'),
                          nullable=False)
    chinese_first_name = db.Column(db.String(50))
    english_first_name = db.Column(db.String(50))
    chinese_last_name = db.Column(db.String(50))
    english_last_name = db.Column(db.String(50))
    birthday = db.Column(db.Integer)
    address = db.Column(db.Text)
    phone = db.Column(db.String(50))
    created = db.Column(db.DateTime, default=datetime.utcnow)
    updated = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    


